/**
 * This file is released under the GNU General Public License.
 * Refer to the COPYING file distributed with this package.
 *
 * Copyright (c) 2008-2009 WURFL-Pro srl
 */
package net.sourceforge.wurfl.core;

import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import net.sourceforge.wurfl.core.resource.ModelDevice;
import net.sourceforge.wurfl.core.resource.WURFLModel;

import org.apache.commons.collections.iterators.ReverseListIterator;
import org.apache.commons.lang.text.StrBuilder;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * <p>
 * Gets the capabilities values iterating over the device hierarchy.
 * </p>
 * <p>
 * 
 * <p>
 * It is intended to those applications need to load few capabilities for each
 * Device. Otherwise This class is very inefficient.
 * </p>
 * 
 * <strong>hierarchy is defined as ordered list from "generic" to root device.<br/>
 * Example:<br/> "generic"->...->root </strong>
 * </p>
 * 
 * @see WURFLModel#getDeviceHierarchy(ModelDevice)
 * 
 * @author WURFL-PRO SRL, Rome, Italy
 * @version $Id: HierarchyCapabilitiesHolder.java 1045 2009-03-09 15:52:53Z filippo.deluca $
 */
public class HierarchyCapabilitiesHolder implements CapabilitiesHolder,
		Serializable {

	/** serial */
	private static final long serialVersionUID = 1L;

	private static final Log log = LogFactory.getLog(HierarchyCapabilitiesHolder.class);

	/**
	 * A ModelDevice hierarchy. To know how is defined hierarchy look at
	 * WURFLModel#getDeviceHierarchy(ModelDevice).
	 */
	private final List hierarchy;

	/**
	 * Build a HierarchyCapabilitiesHolder from ModelDevice hierarchy. To know
	 * how is defined hierarchy look at
	 * WURFLModel#getDeviceHierarchy(ModelDevice).
	 * 
	 * @param hierarchy
	 *            A ModelDevice hierarchy.
	 */
	public HierarchyCapabilitiesHolder(List hierarchy) {
		this.hierarchy = hierarchy;
	}

	/**
	 * Gets capability value iterating over the held ModelDevice hierarchy.
	 */
	public String getCapabilityValue(String capabilityName)
			throws CapabilityNotDefinedException {

		String capabilityValue = null;

		if (log.isTraceEnabled()) {
			StrBuilder logBuilder = new StrBuilder();
			logBuilder.append("Finding capability ").append(capabilityName)
					.append(" accross the device's hierachy...");

			log.trace(logBuilder.toString());
		}

		// Reverse iteration root -> ... -> Generic
		for (Iterator hIt = new ReverseListIterator(hierarchy); hIt.hasNext()
				&& capabilityValue == null;) {
			ModelDevice looperDevice = (ModelDevice) hIt.next();

			if (looperDevice.defineCapability(capabilityName)) {
				capabilityValue = looperDevice.getCapability(capabilityName);
			} else if (Constants.GENERIC.equals(looperDevice.getID())) {
				throw new CapabilityNotDefinedException(capabilityName);
			}

		}

		// Check by loop
		assert capabilityValue != null;
		return capabilityValue;

	}

	/**
	 * Returns all capability for the held ModelDevice.
	 * <p>
	 * <strong>This method is very inefficent. Where the need is to load all
	 * capabilities for one Device, the coiche is
	 * {@link DefaultCapabilitiesHolder}</strong>
	 * </p>
	 */
	public Map getAllCapabilities() {

		Map capabilities = new HashMap();

		log.trace("Building all capability map...");

		/*
		 * WARNING the hierarchy is defined by a ordered list defined as: <code>generic ->
		 * ... -> root</code>.
		 */
		for (Iterator iterator = hierarchy.iterator(); iterator.hasNext();) {
			ModelDevice device = (ModelDevice) iterator.next();
			capabilities.putAll(device.getCapabilities());
		}

		return capabilities;

	}

}
